using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LDNS.Services;
using LDNS.Utilities;
using NLog;

namespace LDNS.Api
{
    /// <summary>
    /// 基于 Named Pipes 的服务端，面向桌面UI进行IPC交互。
    /// 支持多客户端并发连接、会话模式和服务端主动通知功能。
    /// 协议：客户端发送一行命令文本，服务端返回结果文本，末尾追加"__END__"行作为结束标记。
    /// 主动通知格式：以"NOTIFY:"开头，后跟通知内容，末尾追加"__END__"行作为结束标记。
    /// 作者：huobing
    /// </summary>
    public sealed class NamedPipeServer : IDisposable
    {
        public const string DefaultPipeName = "LDNSPipe";

        private readonly Logger _logger = LogManager.GetCurrentClassLogger();
        private readonly CommandExecutor _executor;
        private readonly string _pipeName;
        private CancellationTokenSource? _cts;
        private Task? _listenTask;
        
        /// <summary>
        /// 客户端连接信息模型
        /// 作者：huobing
        /// </summary>
        private class ClientConnection
        {
            public string ClientId { get; }
            public StreamWriter Writer { get; }
            public NamedPipeServerStream ServerStream { get; }
            public bool IsConnected => ServerStream.IsConnected;
            
            public ClientConnection(string clientId, StreamWriter writer, NamedPipeServerStream serverStream)
            {
                ClientId = clientId;
                Writer = writer;
                ServerStream = serverStream;
            }
        }
        
        /// <summary>
        /// 存储活跃的客户端连接
        /// </summary>
        private readonly ConcurrentDictionary<string, ClientConnection> _activeClients = new();

        public NamedPipeServer(LDNS.Interfaces.IDnsService dnsService, DnsConfigManager configManager, string? pipeName = null)
        {
            if (dnsService == null) throw new ArgumentNullException(nameof(dnsService));
            if (configManager == null) throw new ArgumentNullException(nameof(configManager));
            _executor = new CommandExecutor(dnsService, CommandExecutor.CommandSource.UI);
            _pipeName = string.IsNullOrWhiteSpace(pipeName) ? configManager.Config.PipeName : pipeName!;
        }

        /// <summary>
        /// 启动监听循环
        /// </summary>
        public void Start()
        {
            if (_listenTask != null && !_listenTask.IsCompleted) return;
            _cts = new CancellationTokenSource();
            _listenTask = Task.Run(() => ListenLoopAsync(_cts.Token));
            _logger.Info($"NamedPipeServer 已启动，管道名: {_pipeName}");
        }

        /// <summary>
        /// 停止监听循环
        /// </summary>
        public void Stop()
        {
            try
            {
                _cts?.Cancel();
                _listenTask?.Wait(1000);
            }
            catch (Exception ex)
            {
                _logger.Warn(ex, "停止管道服务时出现异常");
            }
            finally
            {
                _cts?.Dispose();
                _cts = null;
                _listenTask = null;
                _logger.Info("NamedPipeServer 已停止");
            }
        }

        private async Task ListenLoopAsync(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                try
                {
                    // 创建命名管道服务器流
                    // 使用PipeOptions.Asynchronous确保异步操作正常工作
                    // 使用PipeOptions.CurrentUserOnly限制只允许当前用户访问，避免权限问题
                    var server = new NamedPipeServerStream(
                        _pipeName,
                        PipeDirection.InOut,
                        NamedPipeServerStream.MaxAllowedServerInstances,
                        PipeTransmissionMode.Message,
                        PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly,
                        0, // 默认输入缓冲区大小
                        0); // 默认输出缓冲区大小
                    
                    _logger.Debug("已创建命名管道服务器流，限制为当前用户访问");

                    _logger.Debug("等待管道连接...");
                    await server.WaitForConnectionAsync(token);
                    _logger.Debug("管道客户端已连接");
                    
                    // 为每个新连接创建一个任务来处理，避免阻塞监听线程
                    // 使用_忽略警告，但添加异常处理确保任务中的异常能被记录
                    _ = Task.Run(async () => 
                    { 
                        try 
                        { 
                            await HandleConnectionAsync(server, token); 
                        } 
                        catch (Exception ex) 
                        { 
                            _logger.Error(ex, "处理客户端连接时发生未捕获的异常"); 
                        } 
                    });
                }
                catch (OperationCanceledException)
                {
                    // 正常退出
                    _logger.Debug("管道监听已取消");
                    break;
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, "管道服务器循环异常，继续下一轮");
                    await Task.Delay(200, token);
                }
            }
        }
        
        /// <summary>
        /// 处理单个客户端连接
        /// 作者：huobing
        /// </summary>
        /// <param name="server">命名管道服务器流</param>
        /// <param name="token">取消令牌</param>
        private async Task HandleConnectionAsync(NamedPipeServerStream server, CancellationToken token)
        {
            if (server == null) return;
            
            // 为每个连接创建唯一的客户端ID用于日志标识
            string clientId = Guid.NewGuid().ToString();
            _logger.Debug($"[客户端 {clientId}] 开始处理连接");
            
            // 创建reader和writer但不使用using，因为需要保存到连接管理器中
            var writer = new StreamWriter(server, Encoding.UTF8, bufferSize: 1024, leaveOpen: true) { AutoFlush = true };
            var reader = new StreamReader(server, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: true);
            
            // 创建客户端连接信息并添加到活跃客户端集合
            var clientConnection = new ClientConnection(clientId, writer, server);
            _activeClients.TryAdd(clientId, clientConnection);
            _logger.Debug($"[客户端 {clientId}] 已添加到活跃客户端列表，当前活跃连接数: {_activeClients.Count}");
            
            try
            {
                // 连接确认（握手），提升客户端感知与可观测性
                await writer.WriteLineAsync("CONNECTED");
                _logger.Debug($"[客户端 {clientId}] 已发送连接确认");
                
                // 支持会话模式，允许单个连接处理多个命令
                while (!token.IsCancellationRequested && server.IsConnected)
                {
                    // 读取一行命令
                    _logger.Debug($"[客户端 {clientId}] 等待命令输入...");
                    string? commandLine = null;
                    _logger.Debug($"[客户端 {clientId}] 开始读取命令行...");
                    try
                    {
                        var readTask = reader.ReadLineAsync();
                        var completed = await Task.WhenAny(readTask, Task.Delay(30000, token)); // 增加超时时间到30秒
                        if (completed != readTask)
                        {
                            _logger.Warn($"[客户端 {clientId}] 读取命令超时，断开连接");
                            SendNotification(clientId, "连接超时，即将断开");
                            await writer.WriteLineAsync("ERROR: 读取命令超时");
                            await writer.WriteLineAsync("__END__");
                            break;
                        }
                        commandLine = await readTask;
                        _logger.Debug($"[客户端 {clientId}] 成功读取到命令行");
                    }
                    catch (OperationCanceledException)
                    {
                        throw;
                    }

                    if (commandLine is null)
                    {
                        _logger.Debug($"[客户端 {clientId}] 客户端已关闭连接，接收到null命令");
                        break;
                    }
                    if (string.IsNullOrWhiteSpace(commandLine))
                    {
                        _logger.Debug($"[客户端 {clientId}] 收到空命令或空白命令，忽略");
                        continue;
                    }
                    
                    // 支持特殊退出命令
                    if (commandLine.Equals("EXIT", StringComparison.OrdinalIgnoreCase))
                    {
                        _logger.Debug($"[客户端 {clientId}] 收到退出命令");
                        await writer.WriteLineAsync("OK: 连接已关闭");
                        await writer.WriteLineAsync("__END__");
                        break;
                    }

                    _logger.Debug($"[客户端 {clientId}] 收到命令: '{commandLine}'");
                    _logger.Debug($"[客户端 {clientId}] 命令长度: {commandLine.Length} 字符");
                    _logger.Debug($"[客户端 {clientId}] 命令哈希码: {commandLine.GetHashCode()}");

                    try
                    {
                        _logger.Debug($"[客户端 {clientId}] 开始执行命令，调用命令执行器");
                        bool ok = _executor.Execute(commandLine, out string result);
                        _logger.Debug($"[客户端 {clientId}] 命令执行完成，结果长度: {(result?.Length ?? 0)} 字符");
                        await writer.WriteLineAsync(result ?? string.Empty);
                        _logger.Debug($"[客户端 {clientId}] 已发送命令结果到客户端");
                        await writer.WriteLineAsync("__END__");
                        _logger.Debug($"[客户端 {clientId}] 已发送结束标记，命令执行完成: {(ok ? "OK" : "ERROR")}");
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex, $"[客户端 {clientId}] 执行管道命令发生异常: {ex.Message}");
                        _logger.Debug($"[客户端 {clientId}] 向客户端发送错误信息");
                        await writer.WriteLineAsync($"ERROR: {ex.Message}");
                        await writer.WriteLineAsync("__END__");
                        _logger.Debug($"[客户端 {clientId}] 已发送错误信息结束标记");
                    }
                }
            }
            catch (OperationCanceledException)
            {
                _logger.Debug($"[客户端 {clientId}] 连接处理已取消");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"[客户端 {clientId}] 处理连接时发生错误");
            }
            finally
            {
                // 从活跃客户端列表中移除并清理资源
                if (_activeClients.TryRemove(clientId, out var connection))
                {
                    _logger.Debug($"[客户端 {clientId}] 从活跃客户端列表中移除，当前活跃连接数: {_activeClients.Count}");
                    try
                    {
                        connection.Writer.Dispose();
                        reader.Dispose();
                        connection.ServerStream.Dispose();
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex, $"[客户端 {clientId}] 清理连接资源时发生错误");
                    }
                }
                _logger.Debug($"[客户端 {clientId}] 连接已关闭");
            }
        }

        /// <summary>
        /// 向特定客户端发送主动通知
        /// 作者：huobing
        /// </summary>
        /// <param name="clientId">客户端ID</param>
        /// <param name="message">通知消息内容</param>
        /// <returns>发送是否成功</returns>
        public async Task<bool> SendNotificationAsync(string clientId, string message)
        {
            if (_activeClients.TryGetValue(clientId, out var client))
            {
                if (client.IsConnected)
                {
                    try
                    {
                        await client.Writer.WriteLineAsync($"NOTIFY:{message}");
                        await client.Writer.WriteLineAsync("__END__");
                        _logger.Debug($"[客户端 {clientId}] 发送通知: {message}");
                        return true;
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex, $"[客户端 {clientId}] 发送通知失败");
                        // 尝试移除失效的连接
                        _activeClients.TryRemove(clientId, out _);
                    }
                }
                else
                {
                    _logger.Warn($"[客户端 {clientId}] 连接已断开，移除失效连接");
                    _activeClients.TryRemove(clientId, out _);
                }
            }
            return false;
        }
        
        /// <summary>
        /// 向所有活跃客户端广播通知
        /// 作者：huobing
        /// </summary>
        /// <param name="message">通知消息内容</param>
        /// <returns>成功发送的客户端数量</returns>
        public async Task<int> BroadcastNotificationAsync(string message)
        {
            int successCount = 0;
            var clientIds = _activeClients.Keys.ToArray(); // 创建副本避免并发修改问题
            
            foreach (var clientId in clientIds)
            {
                if (await SendNotificationAsync(clientId, message))
                {
                    successCount++;
                }
            }
            
            _logger.Debug($"广播通知完成，消息: {message}，成功发送: {successCount}/{clientIds.Length}");
            return successCount;
        }
        
        /// <summary>
        /// 获取当前活跃客户端数量
        /// 作者：huobing
        /// </summary>
        public int ActiveClientCount => _activeClients.Count;
        
        /// <summary>
        /// 获取所有活跃客户端ID列表
        /// 作者：huobing
        /// </summary>
        public IReadOnlyCollection<string> ActiveClientIds => (IReadOnlyCollection<string>)_activeClients.Keys;
        
        /// <summary>
        /// 同步版本：向特定客户端发送通知
        /// 作者：huobing
        /// </summary>
        /// <param name="clientId">客户端ID</param>
        /// <param name="message">通知消息内容</param>
        /// <returns>发送是否成功</returns>
        public bool SendNotification(string clientId, string message)
        {
            return SendNotificationAsync(clientId, message).GetAwaiter().GetResult();
        }
        
        /// <summary>
        /// 同步版本：向所有活跃客户端广播通知
        /// 作者：huobing
        /// </summary>
        /// <param name="message">通知消息内容</param>
        /// <returns>成功发送的客户端数量</returns>
        public int BroadcastNotification(string message)
        {
            return BroadcastNotificationAsync(message).GetAwaiter().GetResult();
        }
        
        public void Dispose()
        {
            Stop();
            
            // 清理所有客户端连接
            foreach (var client in _activeClients.Values)
            {
                try
                {
                    client.Writer.Dispose();
                    client.ServerStream.Dispose();
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, $"[客户端 {client.ClientId}] 清理连接资源时发生错误");
                }
            }
            _activeClients.Clear();
        }
    }
}